package com.oneinlet.config;

import com.alibaba.fastjson.JSON;
import com.oneinlet.component.JsonResult;
import com.oneinlet.interceptor.LoggerHandlerInterceptor;
import org.hibernate.service.spi.ServiceException;
import org.slf4j.Logger;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.NoHandlerFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import org.springframework.http.converter.HttpMessageConverter;
import java.util.ArrayList;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.method.HandlerMethod;
import com.google.gson.stream.MalformedJsonException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerExceptionResolver;
import java.util.Arrays;
import java.util.List;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


/**
 * Created by WangZiHe on 2017/11/5
 * QQ/WeChat:648830605
 * QQ-Group:368512253
 * Blog:www.520code.net
 * Github:https://github.com/yancheng199287
 */


@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Value("${spring.profiles.active}")
    private String env = null;

    @Value("${web.upload-path}")
    private String uploadPath = null;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new JsonMethodArgumentResolver());
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册自定义拦截器，添加拦截路径，排除拦截路径，优先级
        registry.addInterceptor(new LoggerHandlerInterceptor()).addPathPatterns("/**");
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(SerializerFeature.WriteMapNullValue, // 保留空的字段
                SerializerFeature.WriteNullStringAsEmpty, // String null -> ""
                SerializerFeature.WriteNullNumberAsZero, // Number null -> 0
                SerializerFeature.WriteEnumUsingName
                // SerializerFeature.DisableCircularReferenceDetect // 禁止循环引用$ref，原样输出对象
        );
        config.setDateFormat("yyyy-MM-dd HH:mm:ss");
        converter.setFastJsonConfig(config);
        converter.setDefaultCharset(Charset.forName("UTF-8"));
        List<MediaType> list = new ArrayList<>(1);
        list.add(MediaType.APPLICATION_JSON_UTF8);
        converter.setSupportedMediaTypes(list);
        converters.add(converter);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("file:" + uploadPath)
                .addResourceLocations("classpath:/META-INF/resources/").addResourceLocations("classpath:/static/");
    }

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        exceptionResolvers.add((request, response, handler, e) -> {
            JsonResult.Result result = new JsonResult.Result();
            if (e instanceof ServiceException || e instanceof RuntimeException) {// 业务失败的异常，如“账号或密码错误”
                result.code = JsonResult.Status.FAILED.code;
                result.msg = e.getMessage();
                logger.info(e.getMessage());
            } else if (e instanceof NoHandlerFoundException) {
                result.code = JsonResult.Status.NOT_FOUND.code;
                result.msg = "接口 [" + request.getRequestURI() + "] 不存在";
            } else if (e instanceof ServletException) {
                result.code = JsonResult.Status.FAILED.code;
                result.msg = e.getMessage();
            } else if (e instanceof MalformedJsonException) {
                result.code = JsonResult.Status.SERVER_ERROR.code;
                result.msg = "数据解析失败，请检查参数的正确性！";
            } else {
                result.code = JsonResult.Status.SERVER_ERROR.code;
                result.msg = "接口 [" + request.getRequestURI() + "] 内部错误，请联系管理员";
                if (handler instanceof HandlerMethod) {
                    result.msg = String.format("接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s", request.getRequestURI(),
                            ((HandlerMethod) handler).getBean().getClass().getName(), ((HandlerMethod) handler).getMethod().getName(),
                            e.getMessage());
                } else {
                    result.msg = e.getMessage();
                }
                logger.error(result.msg, e);
            }
            //有时候e.message没有消息，需要从这里获取堆栈信息
            if (result.msg == null) {
                result.msg = Arrays.toString(e.getStackTrace());
                logger.error(result.msg, e);
            }
            responseResult(response, result);
            return new ModelAndView();
        });

    }

    private void responseResult(HttpServletResponse response, JsonResult.Result result) {
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setStatus(200);
        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException ex) {
            logger.error(ex.getMessage());
        }
    }

}